#include "GLLineRender.h"
#include "GLRenderComp.h"
#include "RenderController.h"
void GLLineRender::initVAO()
{
	if (mInited)
	{
		return;
	}
	mInited = true;
	// 生成VBO
	glGenBuffers(1, &mRenderDataLine.mVerticesVBO);
	glGenBuffers(1, &mRenderDataLine.mInstanceVBO);
	// 生成VAO
	glGenVertexArrays(1, &mRenderDataLine.mVAO);

	// OpenGL各种Buffer的配置
	glBindVertexArray(mRenderDataLine.mVAO);
	{
		const uint32_t vertexLocation	 = 0; // shader中 qt_Vertex 的索引号
		const uint32_t instanceLocation1 = 1; // shader中 qt_InstanceMatrix 的索引号1。 mat4 要占4个。
		const uint32_t instanceLocation2 = 2; // shader中 qt_InstanceMatrix 的索引号2。 mat4 要占4个。
		const uint32_t instanceLocation3 = 3; // shader中 qt_InstanceMatrix 的索引号3。 mat4 要占4个。
		const uint32_t instanceLocation4 = 4; // shader中 qt_InstanceMatrix 的索引号4。 mat4 要占4个。
											  // 顶点 Buffer的配置
		glBindBuffer(GL_ARRAY_BUFFER, mRenderDataLine.mVerticesVBO);
		{
			glEnableVertexAttribArray(vertexLocation);
			glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), (void*)0);
		}
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		// 变换矩阵的配置
		glBindBuffer(GL_ARRAY_BUFFER, mRenderDataLine.mInstanceVBO);
		{
			glEnableVertexAttribArray(instanceLocation1);
			glVertexAttribPointer(instanceLocation1, 4, GL_FLOAT, GL_FALSE, sizeof(QMatrix4x4), (void*)0);

			glEnableVertexAttribArray(instanceLocation2);
			glVertexAttribPointer(instanceLocation2, 4, GL_FLOAT, GL_FALSE, sizeof(QMatrix4x4), (void*)(sizeof(QVector4D)));

			glEnableVertexAttribArray(instanceLocation3);
			glVertexAttribPointer(instanceLocation3, 4, GL_FLOAT, GL_FALSE, sizeof(QMatrix4x4), (void*)(2 * sizeof(QVector4D)));

			glEnableVertexAttribArray(instanceLocation4);
			glVertexAttribPointer(instanceLocation4, 4, GL_FLOAT, GL_FALSE, sizeof(QMatrix4x4), (void*)(3 * sizeof(QVector4D)));
		}
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		// 变换矩阵的实例化配置，一个图元更新一次，即一条线一个变换矩阵。
		glVertexAttribDivisor(instanceLocation1, 1);
		glVertexAttribDivisor(instanceLocation2, 1);
		glVertexAttribDivisor(instanceLocation3, 1);
		glVertexAttribDivisor(instanceLocation4, 1);
	}
	glBindVertexArray(0);
}
void GLLineRender::updateData()
{
	mRenderDataLine.mVertices.clear();
	// 顶点坐标，默认使用(0,0) -> (1,1) 这条线。
	// 默认坐标就取(0,0) (1,1),方便计算
	// 后面的线要实例化渲染，每条线（每个图元）配一个变换矩阵，通过默认线的坐标进行变换，得到最终坐标。
	// 这样实现，是OpenGL的实例化数组 标准用法。
	QVector3D startZero = QVector3D(0, 0, 0);
	QVector3D stopZero	= QVector3D(1, 1, 0);
	mRenderDataLine.mVertices.append(startZero);
	mRenderDataLine.mVertices.append(stopZero);
	mRenderDataLine.mInstanceMats.clear();
	// 计算变换矩阵
	for (auto comp : gController->comps())
	{
		// 当前线坐标
		auto vertices = comp->mLine->getVertices();

		auto startNow = vertices.at(0);
		auto stopNow  = vertices.at(1);

		// 默认线变换到当前线，需要平移的距离
		QVector3D offset = startNow - startZero;

		// x轴方向的缩放量
		qreal	   scaleX = 1.0f * (stopNow.x() - startNow.x()) / (stopZero.x() - startZero.x());
		qreal	   scaleY = 1.0f * (stopNow.y() - startNow.y()) / (stopZero.y() - startZero.y());
		QMatrix4x4 mat;
		// 这里人为约定 先平移后缩放，方便计算。不需要旋转。
		mat.translate(offset);
		mat.scale(scaleX, scaleY);

		// 叠加一个整体变换的矩阵
		//		mat = comp->mLine->compMat() * mat;

		mRenderDataLine.mInstanceMats.append(mat);
	}
	// 顶点数据从内存传到GPU显存
	glBindBuffer(GL_ARRAY_BUFFER, mRenderDataLine.mVerticesVBO);
	{
		glBufferData(GL_ARRAY_BUFFER, sizeof(QVector3D) * mRenderDataLine.mVertices.size(), mRenderDataLine.mVertices.constData(), GL_STATIC_DRAW);
	}
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	// 矩阵数据从内存传到GPU显存
	glBindBuffer(GL_ARRAY_BUFFER, mRenderDataLine.mInstanceVBO);
	{
		glBufferData(GL_ARRAY_BUFFER, sizeof(QMatrix4x4) * mRenderDataLine.mInstanceMats.size(), mRenderDataLine.mInstanceMats.constData(), GL_STATIC_DRAW);
	}
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void GLLineRender::updateDataByIndex(int index)
{
	if (!inRange(index, 0, gController->comps().size() - 1))
	{
		return;
	}
	auto pLine	  = gController->comps().at(index)->mLine;
	auto vertices = pLine->getVertices();

	QVector3D startZero = QVector3D(0, 0, 0);
	QVector3D stopZero	= QVector3D(1, 1, 0);
	auto	  startNow	= vertices.at(0);
	auto	  stopNow	= vertices.at(1);
	// 默认线变换到当前线，需要平移的距离
	QVector3D offset = startNow - startZero;

	// x轴方向的缩放量
	qreal	   scaleX = 1.0f * (stopNow.x() - startNow.x()) / (stopZero.x() - startZero.x());
	qreal	   scaleY = 1.0f * (stopNow.y() - startNow.y()) / (stopZero.y() - startZero.y());
	QMatrix4x4 mat;
	// 这里人为约定 先平移后缩放，方便计算。不需要旋转。
	mat.translate(offset);
	mat.scale(scaleX, scaleY);
	mRenderDataLine.mInstanceMats[index] = mat;

	gController->makeCurrent();
	{
		// 矩阵数据从内存传到GPU显存
		glBindBuffer(GL_ARRAY_BUFFER, mRenderDataLine.mInstanceVBO);
		{
			glBufferData(GL_ARRAY_BUFFER, sizeof(QMatrix4x4) * mRenderDataLine.mInstanceMats.size(), mRenderDataLine.mInstanceMats.constData(), GL_STATIC_DRAW);
		}
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}
	gController->doneCurrent();
}

void GLLineRender::paint(QOpenGLShaderProgram* program, const QMatrix4x4& mvpMat)
{
	if (!program->bind())
	{
		qWarning() << program->log();
		return;
	}

	glBindVertexArray(mRenderDataLine.mVAO);
	{
		program->setUniformValue("qt_ModelViewProjectionMatrix", mvpMat);
		program->setUniformValue("outColor0", mRenderDataLine.mColor);
		glLineWidth(mRenderDataLine.mLineWidth);
		glDrawArraysInstanced(GL_LINES, 0, 2, mRenderDataLine.mInstanceMats.size());
	}
	glBindVertexArray(0);
}
